/*
 ------------------------------------------------------------------------------
 Copyright (C) 1996-2001 Id Software, Inc.

 This file is part of the Quake source code.

 The Quake source code is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or (at your
 option) any later version.

 The Quake source code is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 more details.

 You should have received a copy of the GNU General Public License along with
 the Quake source code; if not, write to the Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 ------------------------------------------------------------------------------
*/


//
// cg_local.h - local header to all client-game files
//


#ifndef __CG_LOCAL_H__
#define __CG_LOCAL_H__


#include "../game.h"
#include "cg_public.h"


/*
 ==============================================================================

 PARTICLE MANAGER

 ==============================================================================
*/

#define MAX_PARTICLES					1024

struct particle_t {
	char					name[MAX_PATH_LENGTH];

	particle_t *			nextHash;
};

particle_t *	CG_RegisterParticle (const char *name);

void			CG_InitParticles ();
void			CG_ShutdownParticles ();

/*
 ==============================================================================

 FX MANAGER

 ==============================================================================
*/

#define MAX_FXS							1024
#define MAX_FX_ACTIONS					32

struct fxAction_t {
	int todo;
};

struct fx_t {
	char					name[MAX_PATH_LENGTH];

	fx_t *					nextHash;
};

fx_t *			CG_RegisterFX (const char *name);

void			CG_InitFXs ();
void			CG_ShutdownFXs ();

/*
 ==============================================================================

 GLOBALS

 ==============================================================================
*/

#define DEFAULT_FOV					90.0f

#define NUM_CROSSHAIRS				20

struct snapshot_t {
	bool					valid;

	int						time;
	int						ping;
	bool					rateDelayed;
	int						deltaMessage;
	int						messageSequence;

	playerState_t			playerState;

	int						numEntities;
	entityState_t			entityStates[MAX_SNAPSHOT_ENTITIES];
};

struct entity_t {
	entityState_t *			state;				// From cg.snapshot (may be NULL)
	entityState_t *			nextState;			// From cg.nextSnapshot (may be NULL)

	bool					interpolate;		// True if both cg.snapshot and cg.nextSnapshot hold this entity

	bool					lastValid;			// True if it was present in the last frame

	int						eventSequence;

	int						sort;				// For sorting active entities

	// Exact interpolated position and orientation on this frame
	glqVec3					lerpOrigin;
	glqAngles				lerpAngles;
	glqMat3					lerpAxis;

	// Exact interpolated position and orientation on the last frame
	glqVec3					lastLerpOrigin;
	glqAngles				lastLerpAngles;
	glqMat3					lastLerpAxis;

	// Exact extrapolated position and orientation at the time of the snapshot
	glqVec3					snapshotOrigin;
	glqAngles				snapshotAngles;
	glqMat3					snapshotAxis;

	// Clipping information
	glqBounds				absBounds;			// Transformed and expanded for epsilons

	// Automatic looping sound
	soundShader_t *			loopSound;

	// Renderer and sound system data
	int						entityHandle;
	renderEntity_t			renderEntity;

	int						lightHandle;
	renderLight_t			renderLight;

	int						emitterHandle;
	soundEmitter_t			soundEmitter;
};

struct testModel_t {
	bool					active;

	bool					isGun;

	int						entityHandle;
	renderEntity_t			renderEntity;

	// Animation testing
	int						time;
	int						frames;
};

struct testSound_t {
	bool					active;

	bool					played;

	int						emitterHandle;
	soundEmitter_t			soundEmitter;

	soundShader_t *			soundShader;
};

struct testPostProcess_t {
	bool					active;

	material_t *			material;
	float					materialParms[MAX_MATERIAL_PARMS];
};

// The cg_t structure will be cleared during map restarts
struct cg_t {
	int						time;
	int						oldTime;

	float					frameTime;

	snapshot_t *			snapshot;			// cg.snapshot->time <= cg.time
	snapshot_t *			nextSnapshot;		// cg.nextSnapshot->time > cg.time, or NULL

	float					frameInterpolation;	// Linear interpolation

	bool					checkEvents;		// If true, check for entity events
	bool					setupPrediction;	// If true, set up prediction entities

	bool					thisFrameTeleport;
	bool					nextFrameTeleport;

	// Active entities
	int						numActiveEntities;
	entity_t *				activeEntities[MAX_SNAPSHOT_ENTITIES];

	// Prediction state
	bool					validPPS;			// Clear until the first call to CG_PredictPlayerState

	playerState_t			predictedPlayerState;

	entity_t				predictedPlayerEntity;
	entityState_t			predictedPlayerEntityState;

	glqVec3					predictedError;
	int						predictedErrorTime;

	// View height smoothing
	float					viewHeightDelta;
	int						viewHeightTime;

	// Zooming
	bool					zoomed;
	int						zoomTime;

	// View rendering
	renderView_t			renderView;
	glqAngles				renderViewAngles;

	// Development tools
	testModel_t				testModel;
	testSound_t				testSound;
	testPostProcess_t		testPostProcess;
};

// The cgs_t structure holds everything loaded or calculated from the game
// state.
// It will not be cleared during map restarts, allowing all clients to begin
// playing instantly.
struct cgs_t {
	bool					demoPlaying;

	int						clientNum;

	int						processedSnapshot;	// Last snapshot processed
	int						latestSnapshot;		// Last snapshot received

	bool					loading;

	scene_t *				scene;				// Primary render scene

	entity_t *				entities;

	// Information parsed from config strings
	char					levelName[MAX_PATH_LENGTH];

	float					gravity;

	int						musicTrack;

	// Local assets
	gui_t *					loadingGUI;

	material_t *			whiteMaterial;
	material_t *			pauseMaterial;
	material_t *			sbNumberMaterials[2][11];
	material_t *			sbColonMaterial;
	material_t *			sbSlashMaterial;
	material_t *			sbWeaponMaterials[7][8];
	material_t *			sbAmmoMaterials[4];
	material_t *			sbArmorMaterials[3];
	material_t *			sbItemMaterials[6];
	material_t *			sbSigilMaterials[4];
	material_t *			sbFaceMaterials[7][2];
	material_t *			sbFaceInvisibleMaterial;
	material_t *			sbFaceInvulnerableMaterials[2];
	material_t *			sbFaceQuadMaterial;
	material_t *			sbBarMaterial;
	material_t *			sbItemBarMaterial;
	material_t *			sbScoreboardMaterial;
	material_t *			sbDiscMaterial;
	material_t *			crosshairMaterials[NUM_CROSSHAIRS];

	// Game assets specified by the server
	model_t *				gameModels[MAX_GAME_MODELS];
	material_t *			gameMaterials[MAX_GAME_MATERIALS];
	soundShader_t *			gameSoundShaders[MAX_GAME_SOUND_SHADERS];

	// Game state from server
	const char *			configStrings[MAX_CONFIG_STRINGS];

	entityState_t			baselines[MAX_ENTITIES];

	snapshot_t				snapshots[PACKET_BACKUP];
};

extern cg_t					cg;
extern cgs_t				cgs;

extern etClient_t *			etClient;

extern cvar_t *				cg_showSnapshots;
extern cvar_t *				cg_showDeltaEntities;
extern cvar_t *				cg_showPredictionMiss;
extern cvar_t *				cg_showEvents;
extern cvar_t *				cg_skipPrediction;
extern cvar_t *				cg_skipRendering;
extern cvar_t *				cg_predictionErrorDecay;
extern cvar_t *				cg_debugMove;
extern cvar_t *				cg_testModelSpawn;
extern cvar_t *				cg_testModelPitch;
extern cvar_t *				cg_testModelYaw;
extern cvar_t *				cg_testModelRoll;
extern cvar_t *				cg_testModelRotatePitch;
extern cvar_t *				cg_testModelRotateYaw;
extern cvar_t *				cg_testModelRotateRoll;
extern cvar_t *				cg_testModelAnimate;
extern cvar_t *				cg_testGunX;
extern cvar_t *				cg_testGunY;
extern cvar_t *				cg_testGunZ;
extern cvar_t *				cg_viewSize;
extern cvar_t *				cg_fov;
extern cvar_t *				cg_hand;
extern cvar_t *				cg_gunX;
extern cvar_t *				cg_gunY;
extern cvar_t *				cg_gunZ;
extern cvar_t *				cg_crosshair;
extern cvar_t *				cg_crosshairX;
extern cvar_t *				cg_crosshairY;
extern cvar_t *				cg_crosshairSize;
extern cvar_t *				cg_crosshairColor;
extern cvar_t *				cg_crosshairAlpha;
extern cvar_t *				cg_crosshairHealth;
extern cvar_t *				cg_drawGun;
extern cvar_t *				cg_drawHUD;
extern cvar_t *				cg_drawCrosshair;
extern cvar_t *				cg_draw2D;

void			CG_TestModel_f ();
void			CG_TestGun_f ();
void			CG_TestMaterial_f ();
void			CG_TestMaterialParm_f ();
void			CG_TestRemoteView_f ();
void			CG_FirstFrame_f ();
void			CG_LastFrame_f ();
void			CG_PrevFrame_f ();
void			CG_NextFrame_f ();
void			CG_JumpToFrame_f ();
void			CG_TestSound_f ();
void			CG_TestSoundParm_f ();
void			CG_TestPostProcess_f ();
void			CG_TestPostProcessParm_f ();
void			CG_TestDecal_f ();
void			CG_TestSplatDecal_f ();

void			CG_UpdateTestModel ();
void			CG_UpdateTestSound ();
void			CG_UpdateTestPostProcess ();

void			CG_ClearTestModel ();
void			CG_ClearTestSound ();
void			CG_ClearTestPostProcess ();

void			CG_AddCommands ();
void			CG_RemoveCommands ();

void			CG_EntityEvent (entity_t *entity, int eventType, int eventParm);
void			CG_CheckEntityEvents ();

void			CG_AddClipEntity (entity_t *entity, clipModel_t *clipModel, int contents, const glqBounds &bounds);

int				CG_Contents (const glqVec3 &point, const glqBounds &bounds, int contentMask, bool skipAnimations, int passEntityNum);

void			CG_Trace (const glqVec3 &start, const glqVec3 &end, const glqBounds &bounds, int contentMask, bool skipAnimations, int passEntityNum, trace_t *trace);

void			CG_ParseConfig ();

void			CG_SetConfigString (int index, const char *string);

int				CG_WriteGameState (msg_t *msg, int offset);
int				CG_ParseGameState (msg_t *msg);

void			CG_ParseDeltaPlayerState (msg_t *msg, playerState_t *oldState, playerState_t *newState);
void			CG_ParseDeltaEntityState (msg_t *msg, entityState_t *oldState, entityState_t *newState, int number);

bool			CG_ParseSnapshot (msg_t *msg, int sequence, int *time, bool *deltaCompressed);

void			CG_ProcessSnapshots ();

void			CG_ServerCommand ();

void			CG_AddViewWeapon (playerState_t *playerState, entity_t *entity);

void			CG_FireWeaponSound (entity_t *entity);

void			CG_RenderView ();

void			CG_Draw2D ();
void			CG_DrawLoading ();

void			CG_UpdateFrameGraph (int timeDelta);
void			CG_UpdateSnapshotGraph (int ping, bool rateDelayed);

void			CG_BuildActiveEntityList ();

void			CG_SetupEntities ();
void			CG_SetupPredictEntities ();

void			CG_UpdateEntities ();
void			CG_UpdatePlayerEntity ();

void			CG_ClearEntities ();
void			CG_ClearPlayerEntity ();

void			CG_LoadLevel ();
void			CG_FreeLevel ();

void			CG_TransitionPlayerState (playerState_t *oldState, playerState_t *newState);

void			CG_PredictPlayerState ();


#endif	// __CG_LOCAL_H__